﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using HU8.Helpers.Images.Models;
using ZRLabs.Yael.BasicFilters;
using System.Drawing.Drawing2D;

namespace HU8.Helpers.Files.Images
{
    /// <summary>
    /// 图片帮助
    /// 作者：刘勇
    /// </summary>
    public static class ImageHelper
    {
        /// <summary>
        /// 保存缩略图
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="config"></param>
        public static void SaveThumbnail(string imagePath, ThumbnailConfig config = null)
        {
            if (config == null)
            {
                config = new ThumbnailConfig();
            }
            Image img = Image.FromFile(imagePath);
            Image resizedImage = ImageHelper.ResizeImage(img, config);
            img.Dispose();
            ImageHelper.SaveJpeg(imagePath, resizedImage, config.Quality);
        }


        /// <summary>
        /// 存储水印
        /// </summary>
        /// <param name="source"></param>
        /// <param name="watermark"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static Image MakeWatermark(this Image source, WatermarkConfig config)
        {
            if (!string.IsNullOrEmpty(config.ImagePath) && File.Exists(config.ImagePath))
            {
                Image watermark = Image.FromFile(config.ImagePath);
                return MakeWatermark(source, watermark, config.Position, config.Padding, config.Width, config.Height, config.Transparency);
            }
            else
            {
                return source;
            }
        }

        /// <summary>
        /// 存储水印
        /// </summary>
        /// <param name="source"></param>
        /// <param name="watermark"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static Image MakeWatermark(this Image source, Image watermark, WatermarkConfig config = null)
        {
            if (config == null)
            {
                config = new WatermarkConfig();
            }
            return MakeWatermark(source, watermark, config.Position, config.Padding, config.Width, config.Height, config.Transparency);
        }


        /// <summary>
        /// 添加水印
        /// </summary>
        /// <param name="source">源图片</param>
        /// <param name="watermark">水印图片</param>
        /// <param name="position">水印位置</param>
        /// <param name="padding">水印边距</param>
        /// <param name="watermarkWidth">水印宽度</param>
        /// <param name="watermarkHeight">水印高度</param>
        /// <param name="watermarkTransparency">水印不透明度</param>
        /// <returns></returns>
        public static Image MakeWatermark(this Image source, Image watermark, Position position = Position.RightBottom, int padding = 5, int watermarkWidth = 0, int watermarkHeight = 0, int watermarkTransparency = 100)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (watermark == null) throw new ArgumentNullException("watermark");
            if (padding < 0) throw new ArgumentNullException("不能小于0.", "margin");
            if (watermarkWidth < 0) throw new ArgumentNullException("不能小于0.", "watermarkWidth");
            if (watermarkHeight < 0) throw new ArgumentNullException("不能小于0.", "watermarkHeight");
            if (watermarkTransparency < 0) throw new ArgumentNullException("不能小于0.", "watermarkTransparency");
            if (watermarkTransparency > 100) throw new ArgumentNullException("不能大于100.", "watermarkTransparency");

            int px = padding, py = padding;
            if (watermarkWidth == 0) watermarkWidth = watermark.Width;
            if (watermarkHeight == 0) watermarkHeight = watermark.Height;

            #region 计算位置
            switch (position)
            {
                case Position.LeftBottom:
                    py = source.Height - watermarkHeight - py;
                    break;
                case Position.LeftCentre:
                    py = (source.Height - py - watermarkHeight) / 2;
                    break;

                case Position.MiddleBottom:
                    px = (source.Width - px - watermarkWidth) / 2;
                    py = source.Height - watermarkHeight - py;
                    break;
                case Position.MiddleCentre:
                    px = (source.Width - px - watermarkWidth) / 2;
                    py = (source.Height - py - watermarkHeight) / 2;
                    break;
                case Position.MiddleTop:
                    px = (source.Width - px - watermarkWidth) / 2;
                    break;

                case Position.RightBottom:
                    px = source.Width - watermarkWidth - px;
                    py = source.Height - watermarkHeight - py;
                    break;
                case Position.RightCentre:
                    px = source.Width - watermarkWidth - px;
                    py = (source.Height - py - watermarkHeight) / 2;
                    break;
                case Position.RightTop:
                    px = source.Width - watermarkWidth - px;
                    break;
            }
            #endregion

            var rvImg = source.Clone() as Image;
            if (position != Position.NoDisplay)
            {
                using (var g = Graphics.FromImage(rvImg))
                {
                    var imgAttr = new System.Drawing.Imaging.ImageAttributes();
                    float[][] colorMatrixElements = { 
                    new float[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
                    new float[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
                    new float[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
                    new float[] {0.0f,  0.0f,  0.0f,  (float)watermarkTransparency/100, 0.0f},
                    new float[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}
                };
                    imgAttr.SetColorMatrix(new ColorMatrix(colorMatrixElements));

                    g.DrawImage(watermark,
                        new Rectangle(px, py, watermarkWidth, watermarkHeight),
                            0, 0, watermark.Width, watermark.Height,
                        GraphicsUnit.Pixel, imgAttr);
                }
            }
            return rvImg;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="text"></param>
        /// <param name="size"></param>
        /// <param name="color"></param>
        /// <param name="tranparency"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        public static Image MakeWatermarkText(this Image source, string text, int size, Color color, int tranparency, Position position = Position.RightBottom)
        {
            TextWatermarkFilter watermark = new TextWatermarkFilter();
            watermark.Caption = text;
            watermark.Halign = WaterMarkFilter.HAlign.Bottom;
            watermark.Valign = WaterMarkFilter.VAlign.Right;
            watermark.CaptionAlpha = tranparency;
            watermark.CaptionColor = color;
            watermark.TextSize = size;
            watermark.ExecuteFilter(source);
            return source;
        }

        /// <summary>
        /// Resize图片
        /// </summary>
        /// <param name="source"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static Image ResizeImage(this Image source, ThumbnailConfig config)
        {
            return ResizeImage(source, config.Width, config.Height, config.BackgroundColor, config.ResizeStyle, config.MustFit);
        }

        /// <summary>
        /// Resize图片
        /// </summary>
        /// <param name="source"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="backgroundColor"></param>
        /// <param name="style"></param>
        /// <param name="mustFit"></param>
        /// <returns></returns>
        public static Image ResizeImage(this Image source, int width, int height, Color? backgroundColor = null, ResizeStyle style = ResizeStyle.Zoom, bool mustFit = true)
        {
            ResizeFilter resize = new ResizeFilter();
            resize.BackGroundColor = backgroundColor ?? Color.Transparent;
            resize.InterpolationType = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
            double aspectRatio = width / height;

            switch (style)
            {
                case ResizeStyle.Zoom:
                    if (source.Height > source.Width)
                    {
                        resize.LockRatioByHeight = true;
                        resize.KeepAspectRatio = true;
                        resize.Height = height;
                    }
                    else if (source.Width > source.Height)
                    {
                        resize.LockRatioByWidth = true;
                        resize.KeepAspectRatio = true;
                        resize.Width = width;
                    }
                    else
                    {
                        resize.Height = height;
                        resize.Width = width;
                        resize.KeepAspectRatio = true;
                    }
                    source = resize.ExecuteFilter(source);
                    break;
                case ResizeStyle.Stretch:
                    resize.Height = height;
                    resize.Width = width;
                    resize.KeepAspectRatio = false;
                    source = resize.ExecuteFilter(source);
                    break;
                case ResizeStyle.Centre:
                    int cWidth = width;
                    int cHeight = height;
                    //居中裁剪
                    if (width > source.Width)
                    {
                        cWidth = source.Width;
                    }
                    if (height > source.Height)
                    {
                        cHeight = source.Height;
                    }
                    decimal resizePercent = 1;
                    int xPosition = 0;
                    int yPosition = 0;
                    if (source.Width > source.Height)
                    {
                        resizePercent = Convert.ToDecimal(cHeight) / Convert.ToDecimal(source.Height);
                        resize.Height = cHeight;
                        resize.Width = Convert.ToInt16(Convert.ToDecimal(source.Width) * resizePercent);
                        source = resize.ExecuteFilter(source);
                        xPosition = Convert.ToInt16((Convert.ToDecimal(resize.Width) - Convert.ToDecimal(cWidth)) / new Decimal(2));
                    }
                    else
                    {
                        resizePercent = Convert.ToDecimal(cWidth) / Convert.ToDecimal(source.Width);
                        resize.Width = cWidth;
                        resize.Height = Convert.ToInt16(Convert.ToDecimal(source.Height) * resizePercent);
                        source = resize.ExecuteFilter(source);
                        yPosition = Convert.ToInt16((Convert.ToDecimal(resize.Height) - Convert.ToDecimal(cHeight)) / new Decimal(2));
                    }
                    source = CropImage(source, xPosition, yPosition, cWidth, cHeight);
                    break;
                case ResizeStyle.Normal:
                    resize.KeepAspectRatio = true;
                    //TODO:平铺
                    break;
            }
            //宽度，和高度，必须与之一样
            if (mustFit)
            {
                source = CentreImage(source, width, height, resize.BackGroundColor);
            }
            return source;
        }


        /// <summary>
        /// 将图片放在一个空白的width * height的长方形正中间
        /// </summary>
        /// <param name="source"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Image CentreImage(Image source, int width, int height, Color backgroundColor)
        {
            Bitmap b = new Bitmap(width, height);
            using (var g = Graphics.FromImage(b))
            {
                int xPosition = 0;
                int yPosition = 0;
                if (width > source.Width)
                {
                    xPosition = Convert.ToInt16(Convert.ToDecimal(width - source.Width) / new Decimal(2));
                }
                if (height > source.Height)
                {
                    yPosition = Convert.ToInt16(Convert.ToDecimal(height - source.Height) / new Decimal(2));
                }
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.FillRectangle(new SolidBrush(backgroundColor), -1, -1, width + 2, height + 2); //重新画一下背景颜色
                g.DrawImage(source, xPosition, yPosition, source.Width, source.Height);
                g.Save();
                source = (Image)b.Clone();
                b.Dispose();
            }
            return source;
        }


        /// <summary>
        /// 旋转图片
        /// </summary>
        /// <param name="source"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Image RotateImage(Image source, RotateFlipType type)
        {
            Bitmap temp = (Bitmap)source;
            Bitmap bmap = (Bitmap)temp.Clone();
            bmap.RotateFlip(type);
            source = (Bitmap)bmap.Clone();
            bmap.Dispose();
            temp.Dispose();
            return source;
        }

        private static Bitmap RotateImage(Image source, float angle)
        {
            Bitmap b = (Bitmap)source;
            //create a new empty bitmap to hold rotated image
            Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
            //make a graphics object from the empty bitmap
            Graphics g = Graphics.FromImage(returnBitmap);
            //move rotation point to center of image
            g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
            //rotate
            g.RotateTransform(angle);
            //move image back
            g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
            //draw passed in image onto graphics object
            g.DrawImage(b, new Point(0, 0));
            return returnBitmap;
        }


        /// <summary>
        /// 剪切图片
        /// </summary>
        /// <param name="source"></param>
        /// <param name="xPosition"></param>
        /// <param name="yPosition"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public static Image CropImage(Image source, int xPosition, int yPosition, int width, int height)
        {
            Bitmap temp = (Bitmap)source;
            Bitmap bmap = (Bitmap)temp.Clone();
            if (xPosition + width > source.Width)
            {
                width = source.Width - xPosition;
            }
            if (yPosition + height > source.Height)
            {
                height = source.Height - yPosition;
            }
            Rectangle rect = new Rectangle(xPosition, yPosition, width, height);
            source = (Bitmap)bmap.Clone(rect, bmap.PixelFormat);
            bmap.Dispose();
            temp.Dispose();
            return source;
        }


        #region 保存





        /// <summary>
        /// 保存PNG
        /// </summary>
        /// <param name="path"></param>
        /// <param name="img"></param>
        /// <param name="compressionLevel"></param>
        /// <param name="colorDepth"></param>
        public static void SavePng(string path, Image img, int compressionLevel, long colorDepth)
        {
            img.Save(path, GetEncoderInfo("image/png"), GetPngParams(compressionLevel, colorDepth));
        }

        public static EncoderParameters GetPngParams(int compression, long colorDepth)
        {
            if (compression < 0 || compression > 100)
            {
                throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
            }
            // Encoder parameter for image quality
            EncoderParameter compressionParam = new EncoderParameter(Encoder.Compression, compression);
            EncoderParameter colorDepthParam = new EncoderParameter(Encoder.ColorDepth, colorDepth);
            // Jpeg image codec
            EncoderParameters encoderParams = new EncoderParameters(2);
            encoderParams.Param[0] = compressionParam;
            encoderParams.Param[1] = colorDepthParam;
            return encoderParams;
        }

        /// <summary>
        /// 保存Jpeg到文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="img"></param>
        /// <param name="quality"></param>
        public static void SaveJpeg(string path, Image img, int quality)
        {
            //如果文件已存在，删除文件
            if (File.Exists(path))
            {
                File.Delete(path);
            }
            //如果文件夹不存在，则创建文件夹
            string dir = new FileInfo(path).Directory.FullName;
            if(!Directory.Exists(dir)){
                Directory.CreateDirectory(dir);
            }
            img.Save(path, GetEncoderInfo("image/jpeg"), GetJpegParams(quality));
        }

        /// <summary>
        /// 保存Jpeg到内存
        /// </summary>
        /// <param name="img"></param>
        /// <param name="quality"></param>
        /// <returns></returns>
        public static Image SaveJpeg(Image img, int quality)
        {
            Image newImage = null;
            using (MemoryStream s = new MemoryStream())
            {
                Image saveImage = (Image)img.Clone();
                saveImage.Save(s, GetEncoderInfo("image/jpeg"), GetJpegParams(quality));
                newImage = Image.FromStream(s);
            }
            return (Image)newImage.Clone();
        }

        public static EncoderParameters GetJpegParams(int quality)
        {
            if (quality < 0 || quality > 100)
            {
                throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
            }
            // Encoder parameter for image quality
            EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
            // Jpeg image codec
            EncoderParameters encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = qualityParam;
            return encoderParams;
        }

        /// <summary>
        /// Returns the image codec with the given mime type
        /// </summary>
        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            // Get image codecs for all image formats
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            // Find the correct image codec
            for (int i = 0; i < codecs.Length; i++)
                if (codecs[i].MimeType == mimeType)
                    return codecs[i];
            return null;
        }
        #endregion

        public static Position ToPosition(string p)
        {
            Position position = (Position)Enum.Parse(typeof(Position), p);
            return position;
        }

        public static ResizeStyle ToResizeStyle(string s)
        {
            ResizeStyle style = (ResizeStyle)Enum.Parse(typeof(ResizeStyle), s);
            return style;
        }

        public static string SaveImages(string portrait, string imagePath, string userName, ImageFormat imageFormat)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 压缩大小
        /// </summary>
        /// <param name="source"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Bitmap CompressImage(this Image source,int width, int height)
        {
            Bitmap bitmap = (Bitmap)source;

            bitmap = (Bitmap)bitmap.ResizeImage(width, height);

            return bitmap;
        }



        public static Image GetThumbnail(string dSrc, int width, int height)
        {
            Image img = Image.FromFile(dSrc);
            img.ResizeImage(width, height);
            return img;
        }
    }
}
